import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;


public class MemoryMapFileRead {
	
	private static final String FILE_NAME="C:\\sivravis\\dev\\studies\\BOC2014\\codeContest10M.csv";
	private static final String TXN_ID="TXN00000000000000166064312654261";
	public static void main(String[] args) {
//		Scanner sc = new Scanner(System.in);
//		String fileName = sc.next();
		String fileName = FILE_NAME;		
		long lstart = System.nanoTime();
		System.out.println(MemoryMapFileRead.readFile(fileName, TXN_ID));
		long lend = System.nanoTime();
		System.out.println("Elapsed Time in Sec = " +(lend - lstart)/1000000000);
//		sc.close();
	}
	
	public static String readFile(String fileName, String txnId){
		RandomAccessFile memoryMappedFile = null;
		int idataBufferSize = 1024 * 1024*10;
		byte[] data = new byte[idataBufferSize];
		List<Byte> backup = new ArrayList<Byte>();
		String value = null;
		
		try {
			memoryMappedFile = new RandomAccessFile(fileName, "r");
			FileChannel fc = memoryMappedFile.getChannel();
			MappedByteBuffer out = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
			
			int j = 0;
			int chunkCount = 1;
			
			while(out.hasRemaining()){
				data[j] = out.get();
				j++;
				
				// last few bytes can be full line or truncated one.
				// take a back up and use the data by next time.
				if(j >= data.length){
					j--;
					if(backup.size() == 0){
						while(j>0){
							if(data[j] == 10 || data[j] == 13)	{
								break;
							}
							backup.add(data[j]);
							j--;
						}
					}

					value = constructMap(data,j);
					if(value != null)
						return value;
//					System.out.println((chunkCount++) + ". "+ "No of Records Read = " + dataMap.size() );
					j=0;
					data = new byte[idataBufferSize];
				}
				// if backupBuffer size more than 0 
				// add it to the byte buffer.
				if(backup.size() > 0){
					int k = backup.size()-1;
					while (	k>=0	){
						data[j++] = backup.remove(k);
						k--;
					}					
				}				
			}
			value = constructMap(data,j);
//			System.out.println(chunkCount + " times read from memory map." + dataMap.size());
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			try {
				if(memoryMappedFile != null){
					memoryMappedFile.close();
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return value;
	}

private static String constructMap(byte[] data,int j){
	byte b;
	int byteBufSize = 32;
	byte[] byteBuf = new byte[byteBufSize];
	String key = null;
	String value = null;
	int byteBufCount=0;
	
	// iterate till j.
	// during the last chunk this may only few will be filled.
	for (int i = 0; i < j; i++) {
		b = data[i];		
		if(b == 44){
			key = (new String(byteBuf)).trim();
			byteBuf = new byte[byteBufSize];
			byteBufCount = 0;
			continue;
		}	else if( b == 13 || b == 10){
			if(byteBufCount == 0){
				continue;
			}
			value = (new String(byteBuf)).trim();
			byteBuf = new byte[byteBufSize];
			byteBufCount = 0;
			if(key .equals(TXN_ID))
				return value;
			continue;
		}
		byteBuf[byteBufCount++]=b;
	}
	return null;
}
public static void readFile(String fileName){
	RandomAccessFile memoryMappedFile = null;
	byte b;
	int byteBufSize = 32;
	byte[] byteBuf = new byte[byteBufSize];
	String key = null;
	String value = null;
	int byteBufCount=0;
	
	try {
		memoryMappedFile = new RandomAccessFile(fileName, "r");
		FileChannel fc = memoryMappedFile.getChannel();
		MappedByteBuffer out = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
		
		while(out.hasRemaining()){
			b = out.get();
			if(b == 44){
				key = (new String(byteBuf)).trim();
				byteBuf = new byte[byteBufSize];
				byteBufCount = 0;
				continue;
			}	else if( b == 13 || b == 10){
				if(byteBufCount == 0){
					continue;
				}
				value = (new String(byteBuf)).trim();
				if(idMap.containsKey(key)){
					idMap.put(key, value);
				}
				if(idMap.containsKey(value)){
					idMap.put(value, key);
				}
				byteBuf = new byte[byteBufSize];
				byteBufCount = 0;
				continue;
			}
			byteBuf[byteBufCount++]=b;
		}
	} catch (FileNotFoundException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}finally{
		try {
			if(memoryMappedFile != null){
				memoryMappedFile.close();
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

public static String readFileInputStream(String fileName , String txnId){
	FileInputStream fis = null;
	int idataBufferSize = 1024*1024*10;
	byte[] data = new byte[idataBufferSize];
	List<Byte> backup = new ArrayList<Byte>();
	String value = null;
	
	try{
		fis = new FileInputStream(new File(fileName));
		FileChannel fc = fis.getChannel();
		ByteBuffer byteBuf = ByteBuffer.allocate(idataBufferSize);
		int bytesRead = fc.read(byteBuf);
		int chunkCount = 1;
		int j = 0;
		while(bytesRead != -1){			
			byteBuf.flip();
			j = 0;
			while(byteBuf.hasRemaining()){
				data[j] = byteBuf.get();
				j++;
				
				// last few bytes can be full line or truncated one.
				// take a back up and use the data by next time.
				if(j >= bytesRead){
					j--;
					if(backup.size() == 0){
						while(j>0){
							if(data[j] == 10 || data[j] == 13)	{
								break;
							}
							backup.add(data[j]);
							j--;
						}
					}

					value = constructMap(data,j);
					if(value != null)
						return value;

//					System.out.println((chunkCount++) + ". "+ "No of Records Read = " + dataMap.size() );
					j=0;
					data = new byte[idataBufferSize];
				}
				// if backupBuffer size more than 0 
				// add it to the byte buffer.
				if(backup.size() > 0){
					int k = backup.size()-1;
					while (	k>=0	){
						data[j++] = backup.remove(k);
						k--;
					}					
				}
			}
			byteBuf.clear();
			bytesRead = fc.read(byteBuf);			
		}
//		System.out.println(chunkCount + " times read from memory map."  + dataMap);
	}catch(Exception e){
		e.printStackTrace();
	}finally{
		try {
			fis.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	return value;

//		int content = 0;
//		while((content=fis.read()) != -1){
//			System.out.print((char) content);
//		}
}
}
